home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Networking / OTStreamLogViewer1.0b1 / FileLogging.c next >
Encoding:
C/C++ Source or Header  |  1998-03-15  |  7.1 KB  |  274 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        FileLogging.c
  3.  
  4.     Contains:    File logging engine for OTStreamLogViewer.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. #define qDebug 1
  22.  
  23. /////////////////////////////////////////////////////////////////////
  24. // Standard C stuff.
  25.  
  26. #import <stdio.h>
  27.  
  28. /////////////////////////////////////////////////////////////////////
  29. // Pick up standard OT APIs.
  30.  
  31. #import <OpenTransport.h>
  32.  
  33. /////////////////////////////////////////////////////////////////////
  34. // Pick up the low-level OT APIs.
  35.  
  36. #import <OTDebug.h>
  37.  
  38. /////////////////////////////////////////////////////////////////////
  39. // Pick up toolbox stuff.
  40.  
  41. #import <TextUtils.h>
  42. #import <Errors.h>
  43.  
  44. /////////////////////////////////////////////////////////////////////
  45. // Pick up our resource definitions.
  46.  
  47. #import "StreamLogResources.h"
  48.  
  49. /////////////////////////////////////////////////////////////////////
  50. // Pick up our own prototypes.
  51.  
  52. #import "FileLogging.h"
  53.  
  54. /////////////////////////////////////////////////////////////////////
  55. // OTDebugStr is not defined in any OT header files, but it is
  56. // exported by the libraries, so we define the prototype here.
  57.  
  58. extern pascal void OTDebugStr(const char* str);
  59.  
  60. /////////////////////////////////////////////////////////////////////
  61.  
  62. static OSStatus FSWriteQAtLEOF(SInt16 fileRefNum, SInt32 count, void *buffer)
  63.     // Writes the count bytes at buffer to the end of fileRefNum.
  64. {
  65.     ParamBlockRec pb;
  66.  
  67.     pb.ioParam.ioRefNum = fileRefNum;
  68.     pb.ioParam.ioBuffer = buffer;
  69.     pb.ioParam.ioReqCount = count;
  70.     pb.ioParam.ioPosMode = fsFromLEOF;
  71.     pb.ioParam.ioPosOffset = 0;
  72.     
  73.     return PBWriteSync(&pb);
  74. }
  75.  
  76. /////////////////////////////////////////////////////////////////////
  77. // File Logging Stuff
  78.  
  79. static SInt16 gLogFileRefNum = 0;
  80.     // The file refnum of the log file, or 0 if logging
  81.     // is not active.
  82.  
  83. static char gLogAssemblyBuffer[10240];
  84.     // A temporary buffer used to assemble log text 
  85.     // we're about to write to the file.
  86.  
  87. static UInt32 gTicksOfLastFileWrite;
  88.     // The TickCount time at which we last wrote to the file.
  89.     // If TickCount is more than this value plus
  90.     // kTicksPerFlush, we need to flush the file now.
  91.  
  92. enum {
  93.     kTicksPerFlush = 6,
  94.         // Number of ticks from when we write to a file to when
  95.         // we perform a FlushFile to make sure it gets to the disk.
  96.  
  97.     kLogFileCleanTicks = (UInt32) -(kTicksPerFlush+1)
  98.         // When the file is flushed we set gTicksOfLastFileWrite
  99.         // to this value to prevent further writes from happening.
  100.         // This corresponds to "far in the future".    
  101. };
  102.  
  103. static char kStartFileLogString[] = "Sequence\tFlags\tFlags (as number)\tTime (ms)\tReal Time\tModule ID\tStream ID\tMessage\r";
  104.     // When we start logging, we write this line to the file
  105.     // to give the user some idea of the what each column means.
  106.     
  107. extern OSStatus StartFileLogging(void)
  108.     // See comment in interface part.
  109. {
  110.     OSStatus err;
  111.     Str255 logFileName;
  112.     FSSpec logFile;
  113.     
  114.     OTAssert("StartFileLogging: We're already logging!", gLogFileRefNum == 0);
  115.  
  116.     gTicksOfLastFileWrite = kLogFileCleanTicks;
  117.  
  118.     // Open up the log file, creating it if necessary.
  119.         
  120.     GetIndString(logFileName, rMiscStrings, strLogFileName);
  121.     err = FSMakeFSSpec(-1, fsRtDirID, logFileName, &logFile);
  122.     if (err == fnfErr) {
  123.         err = noErr;
  124.     }
  125.     if (err == noErr) {
  126.         (void) FSpCreate(&logFile, 'R*ch', 'TEXT', 0);
  127.         err = FSpOpenDF(&logFile, fsWrPerm, &gLogFileRefNum);
  128.         if (err != noErr) {
  129.             gLogFileRefNum = 0;
  130.         }
  131.     }
  132.     
  133.     // Write the header to the file.
  134.     
  135.     if (err == noErr) {
  136.         err = FSWriteQAtLEOF(gLogFileRefNum, OTStrLength(kStartFileLogString), kStartFileLogString);
  137.     }    
  138.     
  139.     // Clean up.
  140.     
  141.     if (err != noErr) {
  142.         if ( gLogFileRefNum != 0 ) {
  143.             StopFileLogging();
  144.         }
  145.     }
  146.     
  147.     return err;
  148. }
  149.  
  150. enum {
  151.     kFlagsToStringBufferSize = 50
  152.         // flagStr must point to a buffer of at least 50 characters.
  153. };
  154.  
  155. static void FlagsToString(char flags, char *flagStr)
  156.     // Create a verbose string that represents the various
  157.     // flag bits in flags.
  158. {
  159.     flagStr[0] = 0;
  160.  
  161.     if ((flags & SL_TRACE) != 0) {
  162.         OTStrCat(flagStr, "Trace ");
  163.     }
  164.     if ((flags & SL_ERROR) != 0) {
  165.         OTStrCat(flagStr, "Error ");
  166.     }
  167.     if ((flags & SL_CONSOLE) != 0) {
  168.         OTStrCat(flagStr, "Console ");
  169.     }
  170.     
  171.     if ((flags & SL_FATAL) != 0) {
  172.         OTStrCat(flagStr, "Fatal ");
  173.     }
  174.     if ((flags & SL_NOTIFY) != 0) {
  175.         OTStrCat(flagStr, "Notify ");
  176.     }
  177.     if ((flags & SL_WARN) != 0) {
  178.         OTStrCat(flagStr, "Warning ");
  179.     }
  180.     if ((flags & SL_NOTE) != 0) {
  181.         OTStrCat(flagStr, "Notice ");
  182.     }
  183.     
  184.     // Remove the trailing space.
  185.     
  186.     if ( flagStr[0] != 0 ) {
  187.         flagStr[ OTStrLength(flagStr) - 1 ] = 0;
  188.     }
  189. }
  190.  
  191. extern char *LogEntryToCString(LogEntryPtr thisEntry)
  192.     // See comment in interface part.
  193. {
  194.     Str255 dateStr;
  195.     Str255 timeStr;
  196.     char   flagStr[kFlagsToStringBufferSize];
  197.  
  198.     OTAssert("LogEntryToCString: paramErr", thisEntry != nil);
  199.     
  200.     FlagsToString(thisEntry->fLogHeader.flags, flagStr);
  201.  
  202.     // ltime is generated by calling OTGetTimeStamp and converting
  203.     // the result to milliseconds using OTTimeStampInMilliseconds.
  204.     
  205.     // ttime is the result of the low-memory global Time, which
  206.     // is the same as the result of GetDateTime.
  207.  
  208.     DateString(thisEntry->fLogHeader.ttime, shortDate, dateStr, nil);
  209.     TimeString(thisEntry->fLogHeader.ttime, true, timeStr, nil);
  210.  
  211.     sprintf(gLogAssemblyBuffer, "%ld\t%s\t0x%02x\t0x%08x\t%#s %#s\t%d\t%d\t%s\r",
  212.             thisEntry->fLogHeader.seq_no,
  213.             flagStr,
  214.             thisEntry->fLogHeader.flags,
  215.             thisEntry->fLogHeader.ltime,
  216.             dateStr,
  217.             timeStr,
  218.             thisEntry->fLogHeader.mid,
  219.             thisEntry->fLogHeader.sid,
  220.             (char *) thisEntry + sizeof(LogEntry)
  221.         );
  222.     return gLogAssemblyBuffer;
  223. }
  224.  
  225. extern void RecordLogEntryToFile(LogEntryPtr thisEntry)
  226.     // See comment in interface part.
  227. {
  228.     OSStatus junk;
  229.     
  230.     if ( gLogFileRefNum != 0 ) {
  231.     
  232.         (void) LogEntryToCString(thisEntry);
  233.         
  234.         junk = FSWriteQAtLEOF(gLogFileRefNum, OTStrLength(gLogAssemblyBuffer), gLogAssemblyBuffer);
  235.         OTAssert("RecordLogEntryToFile: Error writing log entry", junk == noErr);
  236.         
  237.         gTicksOfLastFileWrite = TickCount();
  238.     }
  239. }
  240.  
  241. extern void FileLoggingIdle(void)
  242.     // See comment in interface part.
  243. {
  244.     OSStatus junk;
  245.     ParamBlockRec pb;
  246.  
  247.     if ( gLogFileRefNum != 0 ) {
  248.         if ( TickCount() > gTicksOfLastFileWrite + kTicksPerFlush ) {
  249.             pb.ioParam.ioRefNum = gLogFileRefNum;
  250.             junk = PBFlushFileSync(&pb);
  251.             OTAssert("DoIdle: FlushFile returned an error", junk == noErr);
  252.             gTicksOfLastFileWrite = kLogFileCleanTicks;
  253.         }
  254.     }
  255. }
  256.  
  257. extern Boolean FileLoggingActive(void)
  258.     // See comment in interface part.
  259. {
  260.     return gLogFileRefNum != 0;
  261. }
  262.  
  263. extern void StopFileLogging(void)
  264.     // See comment in interface part.
  265. {
  266.     OSStatus junk;
  267.     
  268.     OTAssert("StopFileLogging: We're not logging!", gLogFileRefNum != 0);
  269.     
  270.     junk = FSClose(gLogFileRefNum);
  271.     OTAssert("StopFileLogging: Could not close log file", junk == noErr);
  272.     gLogFileRefNum = 0;
  273. }
  274.